// Ben Aksoy
// Performance Test for 3D Game of Life
#include "vtk_include.h"
#include "testGameOfLifeTimer.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>


vtkAssembly* copyAssembly(vtkAssembly *orig)
{
	vtkAssembly *copy=vtkAssembly::New();

	vtkActorCollection *actors = vtkActorCollection::New();
	orig->GetActors(actors);
	actors->InitTraversal();
	for(int i=0; i<actors->GetNumberOfItems(); i++)
	{
		vtkActor *actorCopy = vtkActor::New();
		actorCopy->ShallowCopy(actors->GetNextActor());
		copy->AddPart(actorCopy);
	}
	return copy;
}

void setAssemblyColor(vtkAssembly *assembly,double r, double g, double b)
{
	vtkActorCollection *actors = vtkActorCollection::New();
	assembly->GetActors(actors);
	actors->InitTraversal();
	for(int i=0; i<actors->GetNumberOfItems(); i++)
	{
		actors->GetNextActor()->GetProperty()->SetColor(r,g,b);
	}
}

void buildFrame(vtkRenderer *renderer)
{
	// Create the cylinder source to use for the sides
	vtkCylinderSource *cylinderSource = vtkCylinderSource::New();
	cylinderSource->SetHeight(2*(SIZE+2));
	cylinderSource->SetRadius(.25);
	cylinderSource->SetResolution(20);

	// Create a mapper object
	vtkPolyDataMapper *cylinderMapper = vtkPolyDataMapper::New();
	cylinderMapper->SetInputConnection(cylinderSource->GetOutputPort());

	// lets take a stab at setting the size
	int delta = SIZE+2;
	
	//Associate the mapper to an actor object
	vtkActor *left = vtkActor::New();
	left->SetMapper(cylinderMapper);
	left->SetPosition(-delta,0.0,0.0);

	vtkActor *right = vtkActor::New();
	right->SetMapper(cylinderMapper);
	right->SetPosition(delta,0.0,0.0);

	vtkActor *top = vtkActor::New();
	top->SetMapper(cylinderMapper);
	top->SetPosition(0.0,delta,0.0);
	top->RotateZ(90);

	vtkActor *bottom = vtkActor::New();
	bottom->SetMapper(cylinderMapper);
	bottom->SetPosition(0.0,-delta,0.0);
	bottom->RotateZ(90);

	// put the cylinders together to form one side
	vtkAssembly *frontSide = vtkAssembly::New();
	frontSide->AddPart(left);
	frontSide->AddPart(right);
	frontSide->AddPart(top);
	frontSide->AddPart(bottom);
	frontSide->SetPosition(0,0,delta);
	renderer->AddActor(frontSide);

	// create copies of the side to form the rest
	vtkAssembly *backSide = copyAssembly(frontSide);
	backSide->SetPosition(0,0,-delta);
	renderer->AddActor(backSide);

	vtkAssembly *topSide = copyAssembly(frontSide);
	topSide->RotateX(90);
	topSide->SetPosition(0,delta,0);
	renderer->AddActor(topSide);

	vtkAssembly *bottomSide = copyAssembly(frontSide);
	bottomSide->RotateX(90);
	bottomSide->SetPosition(0,-delta,0);
	renderer->AddActor(bottomSide);
}
int main(void)
{
	printf("initializing...");

	// Create the renderer 
	vtkRenderer *ren1 = vtkRenderer::New();
	ren1->SetBackground(0.1, 0.2, 0.4);

	// add the frame
	buildFrame(ren1);

	//Create a render window
	vtkRenderWindow *renWin = vtkRenderWindow::New();
	renWin->AddRenderer(ren1);
	renWin->SetSize(600,600);

	//Create an interactor and associate it to the render window
	vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
	iren->SetRenderWindow(renWin);
	iren->Initialize();

	//Define the interacting style
	vtkInteractorStyleTrackballCamera *style = vtkInteractorStyleTrackballCamera::New();
	iren->SetInteractorStyle(style);

	//Create and attach callback
	testGameOfLifeTimer *timer = new testGameOfLifeTimer();
	timer->initialize(ren1,iren);
	iren->AddObserver(vtkCommand::TimerEvent,timer);
	timer->setTimerToWatch(iren->CreateRepeatingTimer(1000));

	//Start to interact
	iren->Start();

	printf("\n\ndone!");

	return 0;
}
